/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.support;

import java.io.IOException;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.lang.Nullable;

/**
 * Base class for {@link org.springframework.context.ApplicationContext}
 * implementations which are supposed to support multiple calls to {@link #refresh()},
 * creating a new internal bean factory instance every time.
 * Typically (but not necessarily), such a context will be driven by
 * a set of config locations to load bean definitions from.
 *
 * <p>The only method to be implemented by subclasses is {@link #loadBeanDefinitions},
 * which gets invoked on each refresh. A concrete implementation is supposed to load
 * bean definitions into the given
 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory},
 * typically delegating to one or more specific bean definition readers.
 *
 * <p><b>Note that there is a similar base class for WebApplicationContexts.</b>
 * {@link org.springframework.web.context.support.AbstractRefreshableWebApplicationContext}
 * provides the same subclassing strategy, but additionally pre-implements
 * all context functionality for web environments. There is also a
 * pre-defined way to receive config locations for a web context.
 *
 * <p>Concrete standalone subclasses of this base class, reading in a
 * specific bean definition format, are {@link ClassPathXmlApplicationContext}
 * and {@link FileSystemXmlApplicationContext}, which both derive from the
 * common {@link AbstractXmlApplicationContext} base class;
 * {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
 * supports {@code @Configuration}-annotated classes as a source of bean definitions.
 *
 * @author Juergen Hoeller
 * @author Chris Beams
 * @since 1.1.3
 * @see #loadBeanDefinitions
 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory
 * @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
 * @see AbstractXmlApplicationContext
 * @see ClassPathXmlApplicationContext
 * @see FileSystemXmlApplicationContext
 * @see org.springframework.context.annotation.AnnotationConfigApplicationContext
 */
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

	/**
	 * Whether bean definition overriding is allowed.
	 * 是否允许 BeanDefinition 覆盖。
	 *
	 * 如果为 true（或未显式设置，Spring 默认可能允许），
	 * 当容器中已经存在同名 BeanDefinition 时，后注册的 BeanDefinition 会覆盖之前的定义。
	 *
	 * 如果为 false，则在检测到 BeanDefinition 名称冲突时会抛出异常，防止 Bean 定义被意外覆盖。
	 *
	 * 常见使用场景：
	 * - 开发环境：允许覆盖，方便测试或配置替换。
	 * - 生产环境：通常禁用，避免 Bean 被无意替换导致运行时问题。
	 */
	@Nullable
	private Boolean allowBeanDefinitionOverriding;

	/**
	 * Whether circular references between beans are allowed.
	 * 是否允许 Bean 之间的循环依赖。
	 *
	 * 如果为 true（默认行为），Spring 会通过提前暴露 Bean 的引用来解决构造器或 setter 注入的循环依赖。
	 *
	 * 如果为 false，则在检测到循环依赖时会直接抛出异常，防止出现难以排查的依赖关系问题。
	 *
	 * 常见使用场景：
	 * - 开发环境：默认允许，方便部分业务结构编写。
	 * - 严格模式：禁用，以确保架构中不存在循环依赖。
	 */
	@Nullable
	private Boolean allowCircularReferences;


	/** Bean factory for this context. */
	@Nullable
	private volatile DefaultListableBeanFactory beanFactory;


	/**
	 * Create a new AbstractRefreshableApplicationContext with no parent.
	 * 创建一个没有父容器的 AbstractRefreshableApplicationContext。
	 */
	public AbstractRefreshableApplicationContext() {
	}

	/**
	 * Create a new AbstractRefreshableApplicationContext with the given parent context.
	 * 创建一个带有父容器的 AbstractRefreshableApplicationContext。
	 * @param parent 父容器上下文，用于 Bean 查找的层级委派
	 */
	public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
		super(parent);
	}


	/**
	 * 设置是否允许覆盖 BeanDefinition。
	 *
	 * 允许时（默认 true）：如果注册了一个与现有 BeanDefinition 同名的新定义，会直接替换原来的定义。
	 * 禁止时：检测到同名 BeanDefinition 会抛出异常，防止 Bean 定义被无意覆盖。
	 *
	 * 常见策略：
	 * - 开发/测试：允许覆盖，方便替换 Bean 定义。
	 * - 生产环境：建议禁用，防止配置或代码冲突。
	 *
	 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
	 */
	public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
		this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
	}

	/**
	 * 设置是否允许 Bean 之间的循环依赖。
	 *
	 * 允许时（默认 true）：Spring 会通过提前暴露 Bean 的引用来解析 setter 或构造器注入的循环依赖。
	 * 禁止时：一旦检测到循环依赖，会直接抛出异常。
	 *
	 * 常见策略：
	 * - 开发：允许，方便快速开发。
	 * - 严格架构：禁止，以防止潜在的设计缺陷。
	 *
	 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
	 */
	public void setAllowCircularReferences(boolean allowCircularReferences) {
		this.allowCircularReferences = allowCircularReferences;
	}


	/**
	 * This implementation performs an actual refresh of this context's underlying
	 * bean factory, shutting down the previous bean factory (if any) and
	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
	 *
	 * 本实现执行了对当前上下文底层 BeanFactory 的真正刷新操作，
	 * 包括关闭（销毁）旧的 BeanFactory（如果存在），
	 * 并为上下文生命周期的下一个阶段初始化一个新的 BeanFactory。
	 */
	@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 如果已经有 BeanFactory 实例存在
		if (hasBeanFactory()) {
			// 销毁现有的 Bean 实例
			destroyBeans();
			// 关闭旧的 BeanFactory
			closeBeanFactory();
		}
		try {
			// 创建一个新的 BeanFactory（通常是 DefaultListableBeanFactory）
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 设置序列化ID（用于序列化支持，例如热部署场景）
			beanFactory.setSerializationId(getId());
			// 自定义 BeanFactory（如设置是否允许覆盖、是否允许循环依赖等）
			customizeBeanFactory(beanFactory);
			// 从工厂bean中加载 Bean 定义（如解析 XML、注解或配置类等）
			loadBeanDefinitions(beanFactory);
			// 将新创建并加载完成的 BeanFactory 赋值给上下文的 beanFactory 成员变量
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			// 捕获加载 Bean 定义过程中的 I/O 异常，并抛出上下文异常
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}


	@Override
	protected void cancelRefresh(BeansException ex) {
		DefaultListableBeanFactory beanFactory = this.beanFactory;
		if (beanFactory != null) {
			beanFactory.setSerializationId(null);
		}
		super.cancelRefresh(ex);
	}

	@Override
	protected final void closeBeanFactory() {
		DefaultListableBeanFactory beanFactory = this.beanFactory;
		if (beanFactory != null) {
			beanFactory.setSerializationId(null);
			this.beanFactory = null;
		}
	}

	/**
	 * Determine whether this context currently holds a bean factory,
	 * i.e. has been refreshed at least once and not been closed yet.
	 */
	protected final boolean hasBeanFactory() {
		return (this.beanFactory != null);
	}

	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		DefaultListableBeanFactory beanFactory = this.beanFactory;
		if (beanFactory == null) {
			throw new IllegalStateException("BeanFactory not initialized or already closed - " +
					"call 'refresh' before accessing beans via the ApplicationContext");
		}
		return beanFactory;
	}

	/**
	 * Overridden to turn it into a no-op: With AbstractRefreshableApplicationContext,
	 * {@link #getBeanFactory()} serves a strong assertion for an active context anyway.
	 */
	@Override
	protected void assertBeanFactoryActive() {
	}

	/**
	 * Create an internal bean factory for this context.
	 * Called for each {@link #refresh()} attempt.
	 *
	 * <p>The default implementation creates a
	 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
	 * with the {@linkplain #getInternalParentBeanFactory() internal bean factory} of this
	 * context's parent as parent bean factory. Can be overridden in subclasses,
	 * for example to customize DefaultListableBeanFactory's settings.
	 *
	 * 为当前上下文创建一个内部使用的 BeanFactory。
	 * 每次调用 {@link #refresh()} 时都会调用本方法。
	 *
	 * 默认实现会创建一个 {@link DefaultListableBeanFactory} 实例，
	 * 并将当前上下文父容器的内部 BeanFactory 作为其父 BeanFactory（如果有）。
	 * 子类可重写此方法以自定义 BeanFactory 的属性配置。
	 *
	 * @return 当前上下文所使用的 BeanFactory 实例
	 *
	 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
	 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
	 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
	 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
	 */
	protected DefaultListableBeanFactory createBeanFactory() {
		// 创建 DefaultListableBeanFactory，并设置其父 BeanFactory（如果有）
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}


	/**
	 * Customize the internal bean factory used by this context.
	 * Called for each {@link #refresh()} attempt.
	 * <p>The default implementation applies this context's
	 * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
	 * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
	 * if specified. Can be overridden in subclasses to customize any of
	 * {@link DefaultListableBeanFactory}'s settings.
	 *
	 * 自定义当前上下文使用的内部 BeanFactory。
	 * 每次调用 {@link #refresh()} 时都会执行该方法。
	 *
	 * 默认实现会根据当前上下文的设置（如果有）应用
	 * {@linkplain #setAllowBeanDefinitionOverriding 是否允许 Bean 定义覆盖}
	 * 和 {@linkplain #setAllowCircularReferences 是否允许循环依赖}。
	 *
	 * 子类可以重写此方法，来自定义 {@link DefaultListableBeanFactory} 的任何其他属性。
	 *
	 * @param beanFactory 当前上下文新创建的 BeanFactory 实例
	 * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
	 * @see DefaultListableBeanFactory#setAllowCircularReferences
	 * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
	 * @see DefaultListableBeanFactory#setAllowEagerClassLoading
	 */
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		// 如果设置了是否允许 Bean 定义覆盖，则应用该设置
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// 如果设置了是否允许循环引用，则应用该设置
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}

	/**
	 * Load bean definitions into the given bean factory, typically through
	 * delegating to one or more bean definition readers.
	 * @param beanFactory the bean factory to load bean definitions into
	 * @throws BeansException if parsing of the bean definitions failed
	 * @throws IOException if loading of bean definition files failed
	 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 */
	protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws BeansException, IOException;

}
